home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / GopherTools / jughead / jughead.0.9 / sockets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-24  |  10.7 KB  |  329 lines

  1. /*****************************************************************************
  2.  * File:    sockets.c
  3.  *
  4.  * Author:    Rhett "Jonzy" Jones    jonzy@cc.utah.edu
  5.  *
  6.  * Date:    March 15, 1993
  7.  *
  8.  * Modified:    May 6, 1993, by Rhett "Jonzy" Jones.
  9.  *        Modifed ProcessRequest() to adhere to the gopher protocol
  10.  *        by sending error.host and -1 as the port if we encountered
  11.  *        an error.  Done solely to prevent clients from crashing.
  12.  *
  13.  *        May 18, 1993, by Rhett "Jonzy" Jones.
  14.  *        Added the #ifdef _POSIX_SOURCE in SendString() to prevent
  15.  *        core dumps under A/UX.  Thank you hagberg@cumc.cornell.edu
  16.  *
  17.  * Description:    Contains routines dealing with sockets and communicating
  18.  *        over the internet.
  19.  *
  20.  * Routines:        void    IP2Hostname(int sockfd,char *host,char *ip);
  21.  *            int    SetUpReadNwriter(int theSocket);
  22.  *            void    CloseReadNwriter(void);
  23.  *            int    ContactHost(char* theHost, int thePort);
  24.  *            int    SendString(char *s);
  25.  *            char    *GetString(FILE *ptr);
  26.  *            void    TooMuchTime4Read(void);
  27.  *            void    ChildProcess(void);
  28.  *            int    ListenerEstablished(int port);
  29.  *            int    ProcessRequest(int sockfd);
  30.  *
  31.  * Bugs:    No known bugs.
  32.  *
  33.  * Copyright:    Copyright 1993, University of Utah Computer Center.
  34.  *        This source may be freely distributed as long as this copyright
  35.  *         notice remains intact, and is in no way used for any monetary
  36.  *         gain, by any institution, business, person, or persons.
  37.  *
  38.  ****************************************************************************/
  39.  
  40. #include <setjmp.h>
  41. #include <signal.h>
  42. #include <stdio.h>
  43. #include <sys/types.h>
  44. #include <stdlib.h>
  45. #include <sys/socket.h>
  46. #include <sys/socketvar.h>
  47. #include <netinet/in.h>
  48. #include <netdb.h>
  49. #include <sys/wait.h>
  50. #include <sys/param.h>
  51.  
  52. #define READTIMEOUT    (5 * 60)
  53. #define MAXLINE        512
  54. #define RECVSIZE    4096
  55.  
  56. jmp_buf        env;
  57.  
  58. /* These are defined in "jughead.c". */
  59. extern int        debug;
  60. extern FILE        *wtPtr,
  61.             *rdPtr;
  62. #define BUFFERSIZE    2048
  63. extern char        buffer[BUFFERSIZE];
  64.  
  65. /*****************************************************************************
  66.  * IP2Hostname places the name of the host, as acquired from the IP
  67.  * number, into 'host'.  This way we can log the name of the host instead
  68.  * of the IP number.
  69.  ****************************************************************************/
  70. void IP2Hostname(sockfd,host,ip)
  71.     int            sockfd;        /* Socket file descriptor. */
  72.     char            *host;        /* The name of the host we are talking to. */
  73.     char            *ip;        /* The hosts IP number. */
  74. {    struct sockaddr_in    sin;        /* Info about the socket. */
  75.     int            len;        /* The size of 'sin'. */
  76.     struct hostent        *hostEntry;    /* Information about the host. */
  77.  
  78.     len = sizeof(sin);
  79.     getpeername(sockfd,&sin,&len);
  80.     strcpy(ip,inet_ntoa(sin.sin_addr));
  81.     strcpy(host,inet_ntoa(sin.sin_addr));
  82.  
  83.     hostEntry = gethostbyaddr((char *)&sin.sin_addr,sizeof(sin.sin_addr.s_addr),AF_INET);
  84.      
  85.     if (hostEntry)
  86.         (void)strcpy(host,hostEntry->h_name);
  87.  
  88. }    /* IP2Hostname */
  89.  
  90. /*****************************************************************************
  91.  * SetUpReadNwriter returns true if we can set up read and write pointers
  92.  * to the socket 'theSocket'.
  93.  ****************************************************************************/
  94. int SetUpReadNwriter(theSocket)
  95.     int        theSocket;    /* The socket. */
  96. {
  97.     /* See if we can open a file for writing. */
  98.     if (!(wtPtr = fdopen(theSocket,"w")))
  99.         {
  100.         fprintf(stderr,"error: SetUpReadNwriter could not open socket file for writing.\n");
  101.         return(0);
  102.         }
  103.  
  104.     /* See if we can open a file for reading. */
  105.     if (!(rdPtr = fdopen(theSocket,"r")))
  106.         {
  107.         fprintf(stderr,"error: SetUpReadNwriter could not open socket file for reading.\n");
  108.         return(0);
  109.         }
  110.  
  111.     return(1);
  112.  
  113. }    /* SetUpReadNwriter */
  114.  
  115. /*****************************************************************************
  116.  * CloseReadNwriter simply closes 'rdPtr' and 'wtPtr'.
  117.  ****************************************************************************/
  118. void CloseReadNwriter()
  119. {
  120.     fclose(wtPtr);
  121.     fclose(rdPtr);
  122.  
  123. }    /* CloseReadNwriter */
  124.  
  125. /*****************************************************************************
  126.  * ContactHost returns true if we were able to get a connection to 'theHost'
  127.  * out port 'thePort', and open the files 'wrPtr' and 'rdPtr' for reading and
  128.  * and writing information to and from 'theHost' out 'thePort'.  Otherwise
  129.  * this routine returns false.
  130.  ****************************************************************************/
  131. int ContactHost(theHost,thePort)
  132.     char            *theHost;    /* The host to connect with. */
  133.     int            thePort;    /* The port to use. */
  134. {    int            theSocket;    /* The socket. */
  135.     struct sockaddr_in    scktRec;    /* The socket address info. */
  136.     struct hostent        *theHostEntry;    /* The host entry. */
  137.  
  138.     if (debug)
  139.         fprintf(stderr,"ContactHost attempting a connection to: %s %d\n",theHost,thePort);
  140.  
  141.     /* See if we can get a socket. */
  142.     if ((theSocket = socket(PF_INET,SOCK_STREAM,0)) < 0)
  143.         {
  144.         fprintf(stderr,"error: ContactHost cannot get the socket.\n");
  145.         return(0);
  146.         }
  147.  
  148.     /* Initialize our socket address information. */
  149.     scktRec.sin_family = AF_INET;
  150.     scktRec.sin_port = htons(thePort);
  151.     if (theHostEntry = gethostbyname(theHost))
  152.         bcopy(theHostEntry->h_addr,(char *)&scktRec.sin_addr.s_addr, 4);
  153.     else
  154.         {
  155.         fprintf(stderr,"error: ContactHost found unknown host [%s].\n",theHost);
  156.         return(0);
  157.         }
  158.  
  159.     /* See if we can get a connection. */
  160.     if (connect(theSocket,(struct sockaddr *)&scktRec,sizeof(scktRec)) < 0)
  161.         {
  162.         fprintf(stderr,"error: ContactHost cannot connect to [%s] via port [%d].\n",theHost,thePort);
  163.         return(0);
  164.         }
  165.  
  166.     if (!SetUpReadNwriter(theSocket))
  167.         return(0);
  168.  
  169.     if (debug)
  170.         fprintf(stderr,"ContactHost has established connection\n");
  171.  
  172.     return(1);
  173.  
  174. }    /* ContactHost */
  175.  
  176. /*****************************************************************************
  177.  * SendString returns true no matter what, but first writes the string 's' to
  178.  * 'wtPtr' which is the machine we are talking to.
  179.  ****************************************************************************/
  180. int SendString(s)
  181.     char    *s;    /* The string we are sending to the machine. */
  182. {
  183. #ifdef _POSIX_SOURCE    /* Prevent A/UX from dumping core. */
  184.     fputs(s,wtPtr);
  185. #else
  186.     fprintf(wtPtr,"%s",s);
  187. #endif
  188.     fflush(wtPtr);
  189.     return(1);
  190.  
  191. }    /* SendString */
  192.  
  193. /*****************************************************************************
  194.  * GetString returns a line of text from either the socket or file we are
  195.  * reading from, which is pointed to by the 'ptr'.  The string will contain at
  196.  * most 'BUFFERSIZE' characters.  For more information on the contents of the
  197.  * string returned by this routine consult the man page on 'fgets'.
  198.  ****************************************************************************/
  199. char *GetString(ptr)
  200.     FILE    *ptr;    /* The file or socket we are reading from. */
  201. {
  202.     return(fgets(buffer,BUFFERSIZE,ptr));
  203.  
  204. }    /* GetString */
  205.  
  206. /*****************************************************************************
  207.  * TooMuchTime4Read gets called only when the time period has elapsed when
  208.  * waiting to read from our input..
  209.  ****************************************************************************/
  210. void TooMuchTime4Read()
  211. {
  212.     if (debug)
  213.         fprintf(stderr,"In TooMuchTime4Read\n");
  214.  
  215.     longjmp(env,1);
  216.  
  217. }    /* TooMuchTime4Read */
  218.  
  219. /*****************************************************************************
  220.  * ChildProcess wait3() for a child's return code and status.  This routine
  221.  * is only called by the signal handler after receiving SIGCHLD.
  222.  ****************************************************************************/
  223. void ChildProcess()
  224. {    int    status;        /* Status of the child process. */
  225.  
  226.     while (wait3(&status,WNOHANG|WUNTRACED,NULL) > 0)
  227.         ;
  228.  
  229. }    /* ChildProcess */
  230.  
  231. /*****************************************************************************
  232.  * ListenerEstablished returns -1 if we could NOT: create a socket, set up the socket
  233.  * such that the address will be reused and will stick around for the client,
  234.  * we can bind the socket to the port 'port', and we can set up to listen for
  235.  * up to 5 connections out the port, a socket listening out port 'port'.
  236.  * Otherwise we were able to do all of the above so we return the socket.
  237.  ****************************************************************************/
  238. int ListenerEstablished(port)
  239.     int            port;        /* The port to use. */
  240. {    struct sockaddr_in    sin;        /* The socket information. */
  241.     struct linger        so_linger;    /* The SO_LINGER info. */
  242.     int            so_reuseaddr,    /* The SO_REUSEADDR info. */
  243.                 sckt,        /* The socket to return. */
  244.                 error;        /* Did we get an error? */
  245.  
  246.     if (debug)
  247.         fprintf(stderr,"In ListenerEstablished\n");
  248.  
  249.     /* Initialize the variables. */
  250.     so_reuseaddr = 1;
  251.     error = so_linger.l_onoff = so_linger.l_linger = 0;
  252.     bzero((char *)&sin,sizeof(sin));
  253.     sin.sin_family = AF_INET;
  254.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  255.     sin.sin_port = htons(port);
  256.  
  257.     /* Create a socket binding the same local address and make sure the other will still be around. */
  258.     if ((sckt = socket(AF_INET,SOCK_STREAM,0)) >= 0)
  259.         if (setsockopt(sckt,SOL_SOCKET,SO_REUSEADDR,(char *)&so_reuseaddr,sizeof(so_reuseaddr)) >= 0)
  260.             if (setsockopt(sckt,SOL_SOCKET,SO_LINGER,(char *)&so_linger,sizeof(so_linger)) >= 0)
  261.                 if (bind(sckt,(struct sockaddr *)&sin,sizeof(sin)) >= 0)
  262.                     if (listen(sckt,5) >= 0)
  263.                         return(sckt);
  264.                     else
  265.                         error = fprintf(stderr,"ListenerEstablished: can't listen 5\n");
  266.                 else
  267.                     error = fprintf(stderr,"ListenerEstablished: can't bind\n");
  268.             else
  269.                 error = fprintf(stderr,"ListenerEstablished: can't setsockopt SO_LINGER\n");
  270.         else
  271.             error = fprintf(stderr,"ListenerEstablished: can't setsockopt REUSEADDR!\n");
  272.     else
  273.         error =  fprintf(stderr,"ListenerEstablished: can't socket\n");
  274.  
  275.     return(-error);
  276.  
  277. }    /* ListenerEstablished */
  278.  
  279. /*****************************************************************************
  280.  * ProcessRequest gets and processes a request from a port.
  281.  ****************************************************************************/
  282. int ProcessRequest(sockfd)
  283.     int        sockfd;            /* The socket file descriptor. */
  284. {    char        *inputline;        /* The request to process. */
  285.     int        length;            /* Length of the command line */
  286.  
  287.     if (!SetUpReadNwriter(sockfd))
  288.         {
  289.         fprintf(stderr,"error: ProcessRequest could not setup read and writters\n");
  290.         return(0);
  291.         }
  292.  
  293.     /* Set things up so we don't wait for ever waiting to get a request. */
  294.     (void)signal(SIGALRM,TooMuchTime4Read);
  295.     (void)alarm(READTIMEOUT);
  296.  
  297.     if (setjmp(env))
  298.         {
  299.         SendString("GetString: Timed out!\t\terror.host\t-1\r\n");
  300.         exit(-1);
  301.         }
  302.  
  303.     inputline = GetString(rdPtr);
  304.     length = strlen(inputline);
  305.  
  306.     /* We got our request to deactivate the alarm. */
  307.     (void)alarm(0);
  308.     (void)signal(SIGALRM,SIG_IGN);
  309.  
  310.     if (length <= 0)
  311.         {
  312.         SendString("ProcessRequest: readline error\t\terror.host\t-1\r\n");
  313.         close(sockfd);
  314.         return(0);
  315.         }
  316.  
  317.     RemoveCRLF(inputline);
  318.  
  319.     if (debug)
  320.         fprintf(stderr,"ProcessRequest processing [%s]\n",inputline);
  321.  
  322.     PostPositions(sockfd,inputline);
  323.     SendString(".\r\n");
  324.     CloseReadNwriter();
  325.     return(1);
  326.  
  327. }    /* ProcessRequest */
  328.  
  329.